package services

import (
	"app/common/constant"
	"app/common/validation"
	"app/internal/codec"
	"app/internal/model"
	"app/pkg/config"
	"app/pkg/db"
	"app/pkg/log"
	"app/pkg/sms"
	"errors"
	"fmt"
	"math/rand"
	"net/http"
	"strconv"
	"time"

	"gorm.io/gorm"

	"github.com/gin-gonic/gin"
)

type SendSuccessData struct {
	PhoneNumber string `json:"phone"`
}

type paramsVerificationCode struct {
	Phone   string `form:"phone" json:"phone" validate:"required" label:"手机号码"`         //手机号
	UsedFor int    `form:"usedFor" json:"usedFor" validate:"required"  label:"UserFor"` //1 注册 2 重置密码 3 登录 4 修改手机号
}

// send sms godoc
//
//	@Summary	发送验证码
//	@Schemes
//	@Description
//	@Tags		公共接口
//	@Accept		json
//	@Param		payload	body		paramsVerificationCode	true	"body"
//	@success	200		{object}	response.JSONResult{data=SendSuccessData}
//	@Router		/api/send_sms [post]
func SendVerificationCode(c *gin.Context) {
	params := paramsVerificationCode{}
	if err := codec.GinBind(c, &params); err != nil {
		c.JSON(http.StatusOK, constant.ErrInfo{Code: constant.ParamsError, Msg: err.Error()})
		return
	}
	if !validation.MobileValidator(params.Phone) {
		c.JSON(http.StatusOK, constant.ErrInfo{Code: constant.LogicError, Msg: "手机号格式错误"})
		return
	}
	//加个锁防止快速点击浪费资源
	lockErr := db.DB.Lock(params.Phone)
	if lockErr != nil {
		//锁冲突返回失败
		c.JSON(http.StatusOK, constant.ErrInfo{Code: constant.LogicError, Msg: "操作频繁,请稍后再试"})
		return
	}
	defer db.DB.Unlock(params.Phone)
	//验证短信发送次数
	count := model.NewSmsLogModel().GetSendCountFromRedis(params.Phone, time.Now().Format("20060102"))
	if count > int64(config.Config.AliSMSVerify.SendMaxLimit) {
		c.JSON(http.StatusOK, gin.H{"code": constant.LogicError, "msg": "发送次数超过限制"})
		return
	}
	var accountKey string
	if params.UsedFor == 0 {
		params.UsedFor = constant.VerificationCodeForRegister
	}
	switch params.UsedFor {
	case constant.VerificationCodeForRegister:
		// _, err := model.GetRegisterByPhone(params.Phone)
		// if err == nil {
		// 	log.NewError(c.GetString("requestId"), "The phone number has been registered", params)
		// 	c.JSON(http.StatusOK, gin.H{"code": constant.LogicError, "msg": "手机号已被注册"})
		// 	return
		// }
		accountKey = params.Phone + "_" + constant.VerificationCodeForRegisterSuffix
	//登录校验
	case constant.VerificationCodeForLogin:
		// user, err := model.GetRegisterByPhone(params.Phone)
		// if err != nil || user.Phone == "" {
		// 	log.NewError(c.GetString("requestId"), "账号不存在", params, "err: ", err)
		// 	c.JSON(http.StatusOK, gin.H{"code": constant.LogicError, "msg": "手机号未注册"})
		// 	return
		// }
		accountKey = params.Phone + "_" + constant.VerificationCodeForLoginSuffix
	case constant.VerificationCodeForReset:
		var (
			err   error
			phone string
		)
		user, err2 := model.FindOne[model.UserModel](map[string]interface{}{"phone": params.Phone})
		phone = user.Phone
		err = err2
		if err != nil || phone == "" {
			log.NewError(c.GetString("requestId"), "手机号未注册", params, "err: ", err)
			c.JSON(http.StatusOK, gin.H{"code": constant.LogicError, "msg": "该手机号未注册"})
			return
		}
		accountKey = params.Phone + "_" + constant.VerificationCodeForResetSuffix
	case constant.VerificationCodeForSwitchPhone:
		var (
			err   error
			phone string
		)
		user, err := model.FindOne[model.UserModel](map[string]interface{}{"phone": params.Phone})
		phone = user.Phone
		if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
			log.NewError(c.GetString("requestId"), "db error params: ", params, "err: ", err)
			c.JSON(http.StatusOK, constant.LogicError)
			return
		}
		if phone != "" {
			c.JSON(http.StatusOK, gin.H{"code": constant.LogicError, "msg": "该手机号已被占用"})
			return
		}
		accountKey = params.Phone + "_" + constant.VerificationCodeForSwitchPhoneSuffix
	case constant.VerificationCodeForWechat:
		accountKey = params.Phone + "_" + constant.VerificationCodeForWechatSuffix

	case constant.VerificationCodeForEditPayPass:
		accountKey = params.Phone + "_" + constant.VerificationCodeForEditPayPassSuffix
	}

	if ok, _ := db.DB.JudgeAccountEXISTS(accountKey); ok {
		c.JSON(http.StatusOK, gin.H{"code": constant.LogicError, "msg": "验证码3分钟有效,请勿重复发送"})
		return
	}
	rand.NewSource(time.Now().UnixNano())
	code := 100000 + rand.Intn(899999)
	// client, err := alisms.CreateClient()
	// if err != nil {
	// 	log.NewError(c.GetString("requestId"), "create sendSms client err", "err", err.Error())
	// 	c.JSON(http.StatusOK, constant.ErrServer)
	// 	return
	// }

	// sendSmsRequest := &dysmsapi20170525.SendSmsRequest{
	// 	PhoneNumbers:  tea.String(params.Phone),
	// 	SignName:      tea.String(config.Config.AliSMSVerify.SignName),
	// 	TemplateCode:  tea.String(config.Config.AliSMSVerify.VerificationCodeTemplateCode),
	// 	TemplateParam: tea.String(fmt.Sprintf("{\"code\":\"%d\"}", code)),
	// }

	// response, err := client.SendSms(sendSmsRequest)
	response, err := sms.SendMsg(fmt.Sprintf("%d", code), params.Phone)
	smsLog := model.NewSmsLogModel()
	if err != nil {
		log.NewError(c.GetString("requestId"), "sendSms error", params.Phone, "err", err.Error())
		smsLog.NewItem(params.Phone, strconv.FormatInt(int64(code), 10), 0, err.Error(), c.ClientIP())
		c.JSON(http.StatusOK, gin.H{"code": constant.LogicError, "msg": "短信发送失败,请稍后再试"})
		return
	}
	// if *response.Body.Code != "OK" {
	// 	log.NewError(c.GetString("requestId"), "alibabacloud sendSms error", params.Phone, "err", response.Body.Code, response.Body.Message)
	// 	smsLog.NewItem(params.Phone, strconv.FormatInt(int64(code), 10), 0, fmt.Sprintf("requestId: %s, message: %s", *response.Body.RequestId, *response.Body.Message), c.ClientIP())
	// 	c.JSON(http.StatusOK, gin.H{"code": constant.LogicError, "msg": "短信发送失败,请稍后再试"})
	// 	return
	// }
	if response.Code != "0" {
		log.NewError(c.GetString("requestId"), "alibabacloud sendSms error", params.Phone, "err", fmt.Sprintf("%+v", response))
		smsLog.NewItem(params.Phone, strconv.FormatInt(int64(code), 10), 0, fmt.Sprintf("requestId: %s, message: %s", response.Smsid, response.Msg), c.ClientIP())
		c.JSON(http.StatusOK, gin.H{"code": constant.LogicError, "msg": "短信发送失败,请稍后再试"})
		return
	}
	// 验证码存入redis
	err = db.DB.SetAccountCode(accountKey, code, config.Config.AliSMSVerify.CodeTTL)
	if err != nil {
		log.NewError(c.GetString("requestId"), "set redis error", accountKey, "err", err.Error())
		c.JSON(http.StatusOK, gin.H{"code": constant.LogicError, "msg": "发生错误"})
		return
	}
	//发送记录入库
	err = smsLog.NewItem(params.Phone, strconv.FormatInt(int64(code), 10), 1, "", c.ClientIP())
	if err != nil {
		log.NewError(c.GetString("requestId"), "发送记录入库错误", err.Error())
	}
	//添加发送次数到redis
	model.NewSmsLogModel().IncreSendCountRedis(params.Phone, time.Now().Format("20060102"))
	model.NewSmsLogModel().UpdateExpireSendCount(params.Phone, time.Now().Format("20060102"), 86400)
	data := make(map[string]interface{})
	data["phone"] = params.Phone
	c.JSON(http.StatusOK, gin.H{"code": constant.NoError, "msg": "success", "data": data})
}
